// 用户-资源账号表
package dao

import (
	"encoding/json"
	"fleetmanager/api/model/user"
	"fleetmanager/db/dbm"
	"fleetmanager/security"
	"fleetmanager/setting"
	"fmt"
	"github.com/google/uuid"
	"time"

	"github.com/beego/beego/v2/client/orm"
)

type UserResConf struct {
	Id                    string    `orm:"column(id);size(64);pk" json:"id"`
	OriProjectId          string    `orm:"column(ori_project_id);size(64);" json:"ori_project_id"`
	Username              string    `orm:"column(username);size(64)" json:"username"`
	Userid                string    `orm:"column(user_id);size(64)" json:"user_id"`
	ProjectId             string    `orm:"column(project_id);size(64)" json:"project_id"`
	DomainName            string    `orm:"column(domain_name);size(64)" json:"domain_name"`
	Region                string    `orm:"column(region);size(64)" json:"region"`
	CreationTime          time.Time `orm:"column(creation_time);type(datetime);auto_now_add" json:"creation_time"`
	UpdateTime            time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
	AccessKey             string    `orm:"column(access_key);size(1024)" json:"access_key"`
	SecretAccessKey       string    `orm:"column(secret_access_key);size(1024)" json:"secret_access_key"`
	KeyPairName           string    `orm:"column(key_pair_name);size(64)" json:"key_pair_name"`
	AgencyName            string    `orm:"column(agency_name);size(64)" json:"agency_name"`
	AuxProxyPath          string    `orm:"column(auxproxy_path);size(1024)" json:"aux_proxy_path"`
	BuildScriptPath       string    `orm:"column(build_script_path);size(1024)" json:"build_script_path"`
	DockerBuildScriptPath string    `orm:"column(docker_build_script_path);size(1024)" json:"docker_build_script_path"`
	FileStorageRegion     string    `orm:"column(file_storage_region);size(1024)" json:"file_storage_region"`
}

func (s *UserResConf) TableIndex() [][]string {
	return [][]string{
		{"Userid"},
		{"OriProjectId"},
	}
}

func BuildUserResConf(resConf *user.UserResourceConfig) *UserResConf {
	resUserResConf := UserResConf{
		OriProjectId:          resConf.OriProjectId,
		Username:              resConf.Username,
		Userid:                resConf.UserId,
		ProjectId:             resConf.ProjectId,
		Region:                resConf.Region,
		AccessKey:             resConf.AccessKey,
		SecretAccessKey:       resConf.SecretAccessKey,
		KeyPairName:           resConf.KeypairName,
		DomainName:            resConf.DomainName,
		AgencyName:            resConf.AgencyName,
		AuxProxyPath:          resConf.AuxProxyPath,
		BuildScriptPath:       resConf.BuildScriptPath,
		DockerBuildScriptPath: resConf.DockerBuildScriptPath,
		FileStorageRegion:     resConf.FileStorageRegion,
	}
	return &resUserResConf
}

type userResConfTable struct{}

var urcTable = userResConfTable{}

func GetUserResConf() *userResConfTable {
	return &urcTable
}
func (u *userResConfTable) Get(f Filters) (*UserResConf, error) {
	var resConf UserResConf
	err := f.Filter(UserResConfTable).One(&resConf)
	if err != nil {
		return nil, err
	}
	return &resConf, nil
}

func (u *userResConfTable) Count(f Filters) (int64, error) {
	count, err := f.Filter(UserResConfTable).Count()
	return count, err
}

func (u *userResConfTable) List(limit, offset int) (int, int, []UserResConf, error) {
	var userResConfList []UserResConf
	count, err := dbm.Ormer.QueryTable(UserResConfTable).Limit(limit).Offset(limit * offset).All(&userResConfList)
	if err != nil {
		return 0, 0, nil, err
	}
	total, err := dbm.Ormer.QueryTable(UserResConfTable).Count()
	if err != nil {
		return 0, 0, nil, err
	}
	return int(count), int(total), userResConfList, nil
}

func (u *userResConfTable) ListByUserId(userId string, limit, offset int) (int, int, []UserResConf, error) {
	var userResConfList []UserResConf
	count, err := dbm.Ormer.QueryTable(UserResConfTable).
		Filter("user_id", userId).Limit(limit).Offset(limit * offset).
		All(&userResConfList)
	if err != nil {
		return 0, 0, nil, err
	}
	total, err := dbm.Ormer.QueryTable(UserResConfTable).
		Filter("user_id", userId).Count()
	if err != nil {
		return 0, 0, nil, err
	}
	return int(count), int(total), userResConfList, nil
}

func GetUserResConfByOriProjectId(oriProjectId string) (*UserResConf, error) {
	var u UserResConf
	err := Filters{"OriProjectId": oriProjectId}.Filter(UserResConfTable).One(&u)
	if err != nil {
		return nil, err
	}
	accessKey, err := security.GCM_Decrypt(u.AccessKey, setting.GCMKey, setting.GCMNonce)
	if err != nil {
		return nil, err
	}
	u.AccessKey = accessKey
	secretAccessKey, err := security.GCM_Decrypt(u.SecretAccessKey, setting.GCMKey, setting.GCMNonce)
	if err != nil {
		return nil, err
	}
	u.SecretAccessKey = secretAccessKey
	return &u, nil
}

func GetOriginUserResConfByOriProjectId(oriProjectId string) (*UserResConf, error) {
	var u UserResConf
	err := Filters{"OriProjectId": oriProjectId}.Filter(UserResConfTable).One(&u)
	if err != nil {
		return nil, err
	}
	return &u, nil
}

func GetUserResConfById(id string) (*UserResConf, error) {
	u := UserResConf{}
	err := Filters{"Id": id}.Filter(UserResConfTable).One(&u)
	return &u, err
}

func InsertUserResConfByJson(to orm.TxOrmer, oriProjectId string, resConf *user.UserResourceConfig) error {
	pk, err := uuid.NewUUID()
	if err != nil {
		return fmt.Errorf("get uuid err %+v", err)
	}

	r := *BuildUserResConf(resConf)
	userinfo := User{Id: r.Userid}
	err = dbm.Ormer.Read(&userinfo)
	if err != nil {
		return err
	}
	r.Username = userinfo.UserName
	r.OriProjectId = oriProjectId
	r.Id = pk.String()
	resConf.Username = userinfo.UserName
	resConf.Id = r.Id
	_, err = to.Insert(&r)
	if err != nil {
		_ = to.Rollback()
		return err
	}
	return nil
}

func UpdateUserResConfByJson(to orm.TxOrmer, request []byte, indexId string) error {
	newConfig := UserResConf{}
	if err := json.Unmarshal(request, &newConfig); err != nil {
		return err
	}
	_, err := to.Update(&newConfig, "DomainName", "ProjectId")
	if err != nil {
		_ = to.Rollback()
		return err
	}
	return nil

}

func DeleteUserResConfById(to orm.TxOrmer, indexId string) error {
	userconf := UserResConf{}
	err := Filters{"Id": indexId}.Filter(UserResConfTable).One(&userconf)
	if err != nil {
		return err
	}
	_, err = to.Delete(&userconf)
	if err != nil {
		_ = to.Rollback()
		return fmt.Errorf("delete user resconf err:%s", err.Error())
	}
	return nil
}

func DeleteUserResConf(projectId string, region string) error {
	_, err := Filters{"ProjectId": projectId, "Region": region}.Filter(UserResConfTable).Delete()
	return err
}

func GetAllResConfig(userId string) ([]UserResConf, error) {
	var userResConfList []UserResConf
	o := orm.NewOrm()
	qs := o.QueryTable(UserResConfTable)
	_, err := qs.Filter("user_id", userId).All(&userResConfList)
	if err != nil {
		return nil, err
	}
	return userResConfList, err
}

func GetAllResConfigByMap(queryParams map[string]string) ([]UserResConf, error) {
	var userResConfList []UserResConf
	o := orm.NewOrm()
	cond := orm.NewCondition()
	for key, value := range queryParams {
		if value != "" {
			cond = cond.And(key, value)
		}
	}
	_, err := o.QueryTable(UserResConfTable).SetCond(cond).All(&userResConfList)
	if err != nil {
		return nil, err
	}
	return userResConfList, err
}
